#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void signal_alarm(int signo)
{
    /* nothing to do, just returning wakes up sigsuspend() */
}

int my_sleep(unsigned int nsec)
{
    unsigned int nleft, nret;
    struct sigaction new_action, old_action;
    sigset_t zero_mask, new_mask, old_mask, sus_mask;

    sigemptyset(&zero_mask);
    sigemptyset(&new_mask);
    sigaddset(&new_mask, SIGALRM);

    new_action.sa_handler = signal_alarm;
    new_action.sa_mask = zero_mask;
    new_action.sa_flags = 0;
    sigaction(SIGALRM, &new_action, &old_action);

    sigprocmask(SIG_BLOCK, &new_mask, &old_mask);

    nleft = alarm(0);
    if (nleft > 0 && nleft < nsec && old_action.sa_handler != SIG_IGN)
    {
        nret = nsec - nleft;
        sigaction(SIGALRM, &old_action, NULL);
        alarm(nleft);
        sus_mask = old_mask;
        sigdelset(&sus_mask, SIGALRM);
        sigsuspend(&sus_mask);
        nleft = alarm(0);
        nret += nleft;
        sigprocmask(SIG_SETMASK, &old_mask, NULL);

        return nret;
    }

    alarm(nsec);
    sus_mask = old_mask;
    sigdelset(&sus_mask, SIGALRM);
    sigsuspend(&sus_mask);
    nret = alarm(0);
    sigprocmask(SIG_SETMASK, &old_mask, NULL);

    sigaction(SIGALRM, &old_action, NULL);
    if (nleft > nsec)
        alarm(nleft-nsec);
        
    return nret;
}

int main(int argc, char const* argv[])
{
    signal(SIGALRM, signal_alarm);
    alarm(4);
    my_sleep(3);
    printf("after 3 second\n");
    pause();
    return 0;
}
